programming4us
           
 
 
Programming

iPhone 3D Programming : Vertices and Touch Points - Creating a Wireframe Viewer (part 2)

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
11/23/2010 11:54:29 AM

2. Designing the Interfaces

In the HelloCone and HelloArrow samples, you might have noticed some duplication of logic between the ES 1.1 and ES 2.0 backends. With the wireframe viewer sample, we’re raising the bar on complexity, so we’ll avoid duplicated code by introducing a new C++ component called ApplicationEngine. The application engine will contain all the logic that isn’t coupled to a particular graphics API.

Example 4 shows the contents of Interfaces.hpp, which defines three component interfaces and some related types. Add a new C and C++ header file to your Xcode project called Interfaces.hpp. Replace everything in it with the code shown.

Example 4. Interfaces.hpp
#pragma once
#include "Vector.hpp"
#include "Quaternion.hpp"
#include <vector>

using std::vector;

struct IApplicationEngine {
virtual void Initialize(int width, int height) = 0;
virtual void Render() const = 0;
virtual void UpdateAnimation(float timeStep) = 0;
virtual void OnFingerUp(ivec2 location) = 0;
virtual void OnFingerDown(ivec2 location) = 0;
virtual void OnFingerMove(ivec2 oldLocation, ivec2 newLocation) = 0;
virtual ~IApplicationEngine() {}
};

struct ISurface {
virtual int GetVertexCount() const = 0;
virtual int GetLineIndexCount() const = 0;
virtual void GenerateVertices(vector<float>& vertices) const = 0;
virtual void GenerateLineIndices(vector<unsigned short>& indices) const = 0;
virtual ~ISurface() {}
};

struct Visual {
vec3 Color;
ivec2 LowerLeft;
ivec2 ViewportSize;
Quaternion Orientation;
};

struct IRenderingEngine {
virtual void Initialize(const vector<ISurface*>& surfaces) = 0;
virtual void Render(const vector<Visual>& visuals) const = 0;
virtual ~IRenderingEngine() {}
};

IApplicationEngine* CreateApplicationEngine(IRenderingEngine* renderingEngine);
namespace ES1 { IRenderingEngine* CreateRenderingEngine(); }
namespace ES2 { IRenderingEngine* CreateRenderingEngine(); }



In an effort to move as much logic into the application engine as possible, IRenderingEngine has only two methods: Initialize and Render. We’ll describe them in detail later.

3. Handling Trackball Rotation

To ensure high portability of the application logic, we avoid making any OpenGL calls whatsoever from within the ApplicationEngine class. Example 5 is the complete listing of its initial implementation. Add a new C++ file to your Xcode project called ApplicationEngine.cpp (deselect the option to create the associated .h file). Replace everything in it with the code shown.

Example 5. ApplicationEngine.cpp
#include "Interfaces.hpp"
#include "ParametricEquations.hpp"

using namespace std;

static const int SurfaceCount = 6;

class ApplicationEngine : public IApplicationEngine {
public:
ApplicationEngine(IRenderingEngine* renderingEngine);
~ApplicationEngine();
void Initialize(int width, int height);
void OnFingerUp(ivec2 location);
void OnFingerDown(ivec2 location);
void OnFingerMove(ivec2 oldLocation, ivec2 newLocation);
void Render() const;
void UpdateAnimation(float dt);
private:
vec3 MapToSphere(ivec2 touchpoint) const;
float m_trackballRadius;
ivec2 m_screenSize;
ivec2 m_centerPoint;
ivec2 m_fingerStart;
bool m_spinning;
Quaternion m_orientation;
Quaternion m_previousOrientation;
IRenderingEngine* m_renderingEngine;
};

IApplicationEngine* CreateApplicationEngine(IRenderingEngine* renderingEngine)
{
return new ApplicationEngine(renderingEngine);
}

ApplicationEngine::ApplicationEngine(IRenderingEngine* renderingEngine) :
m_spinning(false),
m_renderingEngine(renderingEngine)
{
}

ApplicationEngine::~ApplicationEngine()
{
delete m_renderingEngine;
}

void ApplicationEngine::Initialize(int width, int height)
{
m_trackballRadius = width / 3;
m_screenSize = ivec2(width, height);
m_centerPoint = m_screenSize / 2;

vector<ISurface*> surfaces(SurfaceCount);
surfaces[0] = new Cone(3, 1);
surfaces[1] = new Sphere(1.4f);
surfaces[2] = new Torus(1.4, 0.3);
surfaces[3] = new TrefoilKnot(1.8f);
surfaces[4] = new KleinBottle(0.2f);
surfaces[5] = new MobiusStrip(1);
m_renderingEngine->Initialize(surfaces);
for (int i = 0; i < SurfaceCount; i++)
delete surfaces[i];
}

void ApplicationEngine::Render() const
{
Visual visual;
visual.Color = m_spinning ? vec3(1, 1, 1) : vec3(0, 1, 1);
visual.LowerLeft = ivec2(0, 48);
visual.ViewportSize = ivec2(320, 432);
visual.Orientation = m_orientation;
m_renderingEngine->Render(&visual);
}

void ApplicationEngine::UpdateAnimation(float dt)
{
}

void ApplicationEngine::OnFingerUp(ivec2 location)
{
m_spinning = false;
}

void ApplicationEngine::OnFingerDown(ivec2 location)
{
m_fingerStart = location;
m_previousOrientation = m_orientation;
m_spinning = true;
}

void ApplicationEngine::OnFingerMove(ivec2 oldLocation, ivec2 location)
{
if (m_spinning) {
vec3 start = MapToSphere(m_fingerStart);
vec3 end = MapToSphere(location);
Quaternion delta = Quaternion::CreateFromVectors(start, end);
m_orientation = delta.Rotated(m_previousOrientation);
}
}

vec3 ApplicationEngine::MapToSphere(ivec2 touchpoint) const
{
vec2 p = touchpoint - m_centerPoint;

// Flip the y-axis because pixel coords increase toward the bottom.
p.y = -p.y;

const float radius = m_trackballRadius;
const float safeRadius = radius - 1;

if (p.Length() > safeRadius) {
float theta = atan2(p.y, p.x);
p.x = safeRadius * cos(theta);
p.y = safeRadius * sin(theta);
}

float z = sqrt(radius * radius - p.LengthSquared());
vec3 mapped = vec3(p.x, p.y, z);
return mapped / radius;
}



The bulk of Example 5 is dedicated to handling the trackball-like behavior with quaternions. I find the CreateFromVectors method to be the most natural way of constructing a quaternion. Recall that it takes two unit vectors at the origin and computes the quaternion that moves the first vector onto the second. To achieve a trackball effect, these two vectors are generated by projecting touch points onto the surface of the virtual trackball (see the MapToSphere method). Note that if a touch point is outside the circumference of the trackball (or directly on it), then MapToSphere snaps the touch point to just inside the circumference. This allows the user to perform a constrained rotation around the z-axis by sliding his finger horizontally or vertically near the edge of the screen.

4. Implementing the Rendering Engine

So far we’ve managed to exhibit most of the wireframe viewer code without any OpenGL whatsoever! It’s time to remedy that by showing the ES 1.1 backend class in Example 6. Add a new C++ file to your Xcode project called RenderingEngine.ES1.cpp (deselect the option to create the associated .h file). Replace everything in it with the code shown.

Example 6. RenderingEngine.ES1.cpp
#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#include "Interfaces.hpp"
#include "Matrix.hpp"

namespace ES1 {


struct Drawable {
GLuint VertexBuffer;
GLuint IndexBuffer;
int IndexCount;
};

class RenderingEngine : public IRenderingEngine {
public:
RenderingEngine();
void Initialize(const vector<ISurface*>& surfaces);
void Render(const vector<Visual>& visuals) const;
private:
vector<Drawable> m_drawables;
GLuint m_colorRenderbuffer;
mat4 m_translation;
};

IRenderingEngine* CreateRenderingEngine()
{
return new RenderingEngine();
}

RenderingEngine::RenderingEngine()
{
glGenRenderbuffersOES(1, &m_colorRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
}

void RenderingEngine::Initialize(const vector<ISurface*>& surfaces)
{
vector<ISurface*>::const_iterator surface;
for (surface = surfaces.begin();
surface != surfaces.end(); ++surface) {

// Create the VBO for the vertices.
vector<float> vertices;
(*surface)->GenerateVertices(vertices);
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER,
vertices.size() * sizeof(vertices[0]),
&vertices[0],
GL_STATIC_DRAW);

// Create a new VBO for the indices if needed.
int indexCount = (*surface)->GetLineIndexCount();
GLuint indexBuffer;
if (!m_drawables.empty() &&
indexCount == m_drawables[0].IndexCount) {
indexBuffer = m_drawables[0].IndexBuffer;
} else {
vector<GLushort> indices(indexCount);
(*surface)->GenerateLineIndices(indices);
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indexCount * sizeof(GLushort),
&indices[0],
GL_STATIC_DRAW);
}

Drawable drawable = { vertexBuffer, indexBuffer, indexCount};
m_drawables.push_back(drawable);
}

// Create the framebuffer object.
GLuint framebuffer;
glGenFramebuffersOES(1, &framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
GL_COLOR_ATTACHMENT0_OES,
GL_RENDERBUFFER_OES,
m_colorRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);

glEnableClientState(GL_VERTEX_ARRAY);
m_translation = mat4::Translate(0, 0, -7);
}

void RenderingEngine::Render(const vector<Visual>& visuals) const
{
glClear(GL_COLOR_BUFFER_BIT);

vector<Visual>::const_iterator visual = visuals.begin();
for (int visualIndex = 0;
visual != visuals.end();
++visual, ++visualIndex)
{
// Set the viewport transform.
ivec2 size = visual->ViewportSize;
ivec2 lowerLeft = visual->LowerLeft;
glViewport(lowerLeft.x, lowerLeft.y, size.x, size.y);

// Set the model-view transform.
mat4 rotation = visual->Orientation.ToMatrix();
mat4 modelview = rotation * m_translation;
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(modelview.Pointer());

// Set the projection transform.
float h = 4.0f * size.y / size.x;
mat4 projection = mat4::Frustum(-2, 2, -h / 2, h / 2, 5, 10);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(projection.Pointer());

// Set the color.
vec3 color = visual->Color;
glColor4f(color.x, color.y, color.z, 1);

// Draw the wireframe.
int stride = sizeof(vec3);
const Drawable& drawable = m_drawables[visualIndex];
glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
glVertexPointer(3, GL_FLOAT, stride, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
glDrawElements(GL_LINES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
}
}

}


There are no new OpenGL concepts here; you should be able to follow the code in Example 3-15. We now have all the big pieces in place for the wireframe viewer. At this point, it shows only a single wireframe; this is improved in the coming sections.

Other -----------------
- iPhone 3D Programming : Vertices and Touch Points - Boosting Performance with Vertex Buffer Objects
- iPhone 3D Programming : Vertices and Touch Points - Saving Memory with Vertex Indexing
- iPhone 3D Programming : Vertices and Touch Points - Reading the Touchscreen
- iPhone 3D Programming : HelloCone with Shaders
- Search Engine Basics : Country-Specific Search Engines
- Search Engine Basics : Vertical Search Engines
- Building Android Apps : Animation - Adding the Settings Panel
- Building Android Apps : Animation - Adding the New Entry Panel
- Building Android Apps : Animation - Adding the Date Panel
- Building Android Apps : Animation - Adding the Dates Panel
- Building Android Apps : Animation - Sliding Home
- Programming Windows Azure : Understanding the Value of Queues
- Programming Windows Azure : Table Operations - Deleting Tables, Deleting Entities
- Programming Windows Azure : Table Operations - Updating Entities
- Programming Windows Azure : Table Operations - Understanding Pagination
- Programming Windows Azure : Table Operations - Using Partitioning
- Programming Windows Azure : Table Operations - Querying Data
- Programming Windows Azure : Table Operations - Creating Entities
- Programming Windows Azure : Table Operations - Creating Tables
- iPad Development : Document Management (part 2)
 
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us